/*
 * $Id: string_strtodn.c,v 1.11 2006-01-17 15:49:22 bacon Exp $
 */

#if defined(__MSTRING)
#include <xp/bas/mstring.h>
#elif defined(__WSTRING)
#include <xp/bas/wstring.h>
#else
#include <xp/bas/string.h>
#endif
#include <xp/bas/locale.h>
#include <xp/bas/assert.h>

xp_size_t xp_strtodn (const xp_char_t* str, xp_byte_t* buf, xp_size_t bufsz)
{
#if defined(__MSTRING)
	const xp_mchar_t* ep;
#elif defined(__WSTRING)
	const xp_wchar_t* ep;
#else
	const xp_char_t* ep;
#endif
	xp_byte_t* bp = buf, * be = buf + bufsz;
	xp_bool_t need_to_advance = xp_false;

	xp_assert (xp_sizeof(xp_byte_t) == xp_sizeof(xp_mchar_t));

	while (*str != XP_CHAR('\0')) {
		if (need_to_advance) str++;
		else need_to_advance = xp_true;

		ep = str; while (*ep != XP_CHAR('\0') && *ep != XP_CHAR('.')) ep++;
		if (ep - str > 63) return 0;

		if (bp < be) *bp++ = (xp_byte_t)(ep - str);
		while (str < ep) {
#if defined(__MSTRING) || defined(XP_CHAR_IS_MCHAR)
			if (bp < be) *bp++ = *str;
#else
			xp_mchar_t mc;
			if (xp_wctomc(*str, &mc, xp_sizeof(mc)) == 0) return 0;
			if (bp < be) *bp++ = mc;
#endif
			str++;
		}
	}

	if (bp < be) *bp = 0;
	return bp - buf + 1;
}

xp_size_t xp_strxtodn (
	const xp_char_t* str, xp_size_t len, xp_byte_t* buf, xp_size_t bufsz)
{
#if defined(__MSTRING)
	const xp_mchar_t* ep, * end;
#elif defined(__WSTRING)
	const xp_wchar_t* ep, * end;
#else
	const xp_char_t* ep, * end;
#endif
	xp_byte_t* bp = buf, * be = buf + bufsz;
	xp_bool_t need_to_advance = xp_false;

	xp_assert (xp_sizeof(xp_byte_t) == xp_sizeof(xp_mchar_t));

	end = str + len;
	while (str < end) {
		if (need_to_advance) str++;
		else need_to_advance = xp_true;

		ep = str; while (ep < end && *ep != XP_CHAR('.')) ep++;
		if (ep - str > 63) return 0;

		if (bp < be) *bp++ = (xp_byte_t)(ep - str);

		while (str < ep) {
#if defined(__MSTRING) || defined(XP_CHAR_IS_MCHAR)
			if (bp < be) *bp++ = *str;
#else
			xp_mchar_t mc;
			if (xp_wctomc(*str, &mc, xp_sizeof(mc)) == 0) return 0;
			if (bp < be) *bp++ = mc;
#endif
			str++;
		}
	}

	if (bp < be) *bp = 0;
	return bp - buf + 1;
}

xp_size_t xp_strfromdn (
	const xp_byte_t* dn, xp_size_t dnsz, xp_char_t* buf, xp_size_t bufsz)
{
	const xp_byte_t* dp, * de, * xe;
#if defined(__MSTRING)
	xp_mchar_t* bp, * be;
#elif defined(__WSTRING)
	xp_wchar_t* bp, * be;
#else
	xp_char_t* bp, * be;
#endif

	xp_assert (xp_sizeof(xp_byte_t) == xp_sizeof(xp_mchar_t));

	dp = dn; de = dn + dnsz - 1;
	bp = buf; be = buf + bufsz - 1;

	while (dp <= de) {
		if (*dp == 0 && dp == de) break;
		if (dp > dn && bp < be) *bp++ = XP_CHAR('.');
		xe = dp + *dp; dp++;
		while (dp <= de && dp <= xe) {
			if (bp < be) {
#if defined(__MSTRING) || defined(XP_CHAR_IS_MCHAR)
				*bp++ = *dp;
#else
				xp_wchar_t wc;
				if (xp_mctowc((xp_mchar_t*)dp, xp_sizeof(*dp), &wc) == 0) return 0;
				*bp++ = wc;
#endif
			}
			dp++;
		}
	}

	*bp = XP_CHAR('\0');
	return bp - buf;
}

xp_size_t xp_strxfromdn (
	const xp_byte_t* dn, xp_size_t dnsz, xp_char_t* buf, xp_size_t bufsz)
{
	const xp_byte_t* dp, * de, * xe;
#if defined(__MSTRING)
	xp_mchar_t* bp, * be;
#elif defined(__WSTRING)
	xp_wchar_t* bp, * be;
#else
	xp_char_t* bp, * be;
#endif

	xp_assert (xp_sizeof(xp_byte_t) == xp_sizeof(xp_mchar_t));

	dp = dn; de = dn + dnsz - 1;
	bp = buf; be = buf + bufsz;

	while (dp <= de) {
		if (*dp == 0 && dp == de) break;
		if (dp > dn && bp < be) *bp++ = XP_CHAR('.');
		xe = dp + *dp; dp++;
		while (dp <= de && dp <= xe) {
			if (bp < be) {
#if defined(__MSTRING) || defined(XP_CHAR_IS_MCHAR)
				*bp++ = *dp;
#else
				xp_wchar_t wc;
				if (xp_mctowc((xp_mchar_t*)dp, xp_sizeof(*dp), &wc) == 0) return 0;
				*bp++ = wc;
#endif
			}
			dp++;
		}
	}

	return bp - buf;
}
